﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;
using SolutionFramework.Entities;
using System.Drawing.Imaging;
using System.IO;
using System.Timers;
using System.Threading;
using System.Diagnostics;

/*
 * IMPORTANT NOTE!
 * 
 * The file ImageService.svc cannot exist within the SolutionFramework.Web project.  If it exists
 * there, it causes VS to crash on build of the Silverlight project. A post build task copies
 * from here to the Web project.
 */

namespace SolutionFramework.Web.ImageService
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ImageService : IImageService
    {
        private static Dictionary<Guid, long> editorPings;
        public static System.Timers.Timer timer;
        const int MINUTE = 1000 * 60;

        public ImageService()
        {
            if (editorPings == null)
            {
                editorPings = new Dictionary<Guid, long>();

                timer = new System.Timers.Timer(MINUTE);
                timer.Elapsed += new ElapsedEventHandler(TimerElapsed);

                timer.Start();
            }
        }

        public void UploadTreeNodeImage(Guid key, string fileName, byte[] imageData)
        {
            var entities = new SolutionFrameworkEntities();

            var image = new TreeNodeImage
            {
                ImageKey = key,
                ImageFormat = FormatFromFileName(fileName),
                FileName = fileName,

                ImageData = imageData
            };

            entities.TreeNodeImages.AddObject(image);

            entities.SaveChanges();
        }

        public string ExtensionFromFormat(Guid format)
        {
            if (ImageFormat.Jpeg.Guid.Equals(format))
            {
                return "jpg";
            }
            else if (ImageFormat.Gif.Equals(format))
            {
                return "gif";
            }
            else if (ImageFormat.Png.Equals(format))
            {
                return "png";
            }
            else if (ImageFormat.Bmp.Equals(format))
            {
                return "bmp";
            }
            else if (ImageFormat.Tiff.Equals(format))
            {
                return "tif";
            }

            return null;
        }

        public Guid? FormatFromFileName(string fileName)
        {
            var ext = Path.GetExtension(fileName);

            if (ext.IndexOf('.') >= 0)
                ext = ext.Substring(ext.LastIndexOf('.') + 1);
            switch (ext.ToLower())
            {
                case "jpg": return (Guid?)ImageFormat.Jpeg.Guid;
                case "gif": return (Guid?)ImageFormat.Gif.Guid;
                case "png": return (Guid?)ImageFormat.Png.Guid;
                case "bmp": return (Guid?)ImageFormat.Bmp.Guid;
                case "tif": return (Guid?)ImageFormat.Tiff.Guid;
            }
            return null;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            Monitor.Enter(editorPings);

            var remove = new List<Guid>();

            foreach (var editorPing in editorPings)
            {
                Debug.WriteLine("Clean up sweep");

                if (System.Environment.TickCount - editorPing.Value > (MINUTE * 5))
                {
                    Debug.WriteLine("Time out");
                    remove.Add(editorPing.Key);
                }
            }

            foreach (var key in remove)
            {
                editorPings.Remove(key);
            }

            Monitor.Exit(editorPings);
        }

        public void CancelUpload(Guid key)
        {
            Monitor.Enter(editorPings);

            Debug.WriteLine("Upload cancelled");

            if (editorPings.ContainsKey(key))
            {
                editorPings[key] = Environment.TickCount - (MINUTE * 3);
            }
            else
            {
                editorPings.Add(key, System.Environment.TickCount);
            }

            Monitor.Exit(editorPings);
        }

        public void Ping(Guid key)
        {
            Monitor.Enter(editorPings);

            Debug.WriteLine("Ping");

            if (editorPings.ContainsKey(key))
            {
                editorPings[key] = System.Environment.TickCount;
            }
            else
            {
                editorPings.Add(key, System.Environment.TickCount);
            }

            Monitor.Exit(editorPings);
        }

        public bool IsUploadCancelled(Guid key)
        {
            Monitor.Enter(editorPings);

            Debug.WriteLine("Query IsUploadCancelled");

            if (editorPings.ContainsKey(key))
            {
                var lastPing = editorPings[key];

                if (System.Environment.TickCount - lastPing > MINUTE)
                {
                    editorPings.Remove(key);
                    Monitor.Exit(editorPings);

                    return true;
                }
            }
            else
            {
                editorPings.Add(key, System.Environment.TickCount);
            }

            Monitor.Exit(editorPings);

            return false;
        }
    }
}
